<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <base href="http://127.0.0.1:4000/" />
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>markdown-it 生成 toc</title>
  <meta name="keywords" content="toc" />
  <meta name="description" content="toc" />
  <link rel="stylesheet" href="static/pages/article_details/index.css?v=1.0.0.2022.08.13 10:12:50">
</head>

<body class="daytime-theme">

  <div class="components_header-wrap">
  <div id="components_header-fix">
    <div class="header clearfix">
      <a class="logo fl" href="/">EOWAY.CN</a>

      <div class="menu-toggle-button fr">导航</div>
      <div class="menu-wrap fr">
        <a class="menu-item" href="/">首页</a>
        <a class="menu-item" href="/about.html">关于</a>
        <div class="menu-item switch-theme-wrap">
          <span>切换主题</span>
          <div id="theme-list">
            <div class="theme-list-item" theme="daytime-theme" >日间</div>
            <div class="theme-list-item" theme="night-theme">夜间</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

  <div class="page-container">
    
<div class="layout-container clearfix">
  <div class="main-wrap">
    <div class="head-wrap">
      <h1 class="title">markdown-it 生成 toc</h1>
      <p class="date">2021-08-11 18:15:05</p>
    </div>
    <div class="markdown-body"><blockquote>
<p>在开始之前，建议先去官网看一下修改渲染规则的例子。
然后使用<code>markdownIt.parse</code> api 生成 token 数组，看下 token 数组结构，这会让你更好的理解下面的代码是如何工作的。</p>
</blockquote>
<h1 id="item-1">修改渲染规则</h1>
<p><code>markdownIt.render</code> api 会遍历 token，当遍历到<code>heading_open</code>时，修改标题标签<code>heading_open</code>的渲染规则，在标签内添加<code>name</code>属性值作为锚点。</p>
<pre><code class="language-javascript">const fs = require('fs')
const path = require('path')
const markdownIt = require('markdown-it')({
  html: true // 源码启用html标签
})

var toc = []

// 如果覆盖，或者是对默认渲染器的代理，则记住老的渲染器。
var defaultRender = markdownIt.renderer.rules.heading_open || function (tokens, idx, options, env, self) {
  return self.renderToken(tokens, idx, options);
};

markdownIt.renderer.rules.heading_open = function (tokens, idx, options, env, self) {
  // 设置锚点
  if (tokens[idx + 1] &amp;&amp; tokens[idx + 1].content) {
    var item = {
      anchor: `item-${toc.length + 1}`,
      // 级别
      rank: tokens[idx].tag.match(/^h([1-9]+)$/)[1],
      name: tokens[idx + 1].content
    }
    var aIndex = tokens[idx].attrIndex('id');
    if (aIndex &lt; 0) {
      tokens[idx].attrPush(['id', item.anchor]); // 设置锚点
    } else {
      tokens[idx].attrs[aIndex][1] = item.anchor; // 替换锚点
    }
    toc.push(item)
  }
  // 传递 token 到默认的渲染器。
  return defaultRender(tokens, idx, options, env, self);
};

// markdown
var content = `
# 一层
文本
## 二层
文本
`
var html = markdownIt.render(content)
var ast = markdownIt.parse(content)

console.log(JSON.stringify(html))
console.log(JSON.stringify(toc))

// fs.writeFileSync('./html.html', html)
// fs.writeFileSync('./toc.js', `module.exports = ${JSON.stringify(toc)}`)
// fs.writeFileSync('./ast.js', `module.exports = ${JSON.stringify(ast)}`)
</code></pre>
<h1 id="item-2">结果</h1>
<p>生成的toc：</p>
<pre><code class="language-json">[{&quot;anchor&quot;:&quot;item-1&quot;,&quot;rank&quot;:&quot;1&quot;,&quot;name&quot;:&quot;一层&quot;},{&quot;anchor&quot;:&quot;item-2&quot;,&quot;rank&quot;:&quot;2&quot;,&quot;name&quot;:&quot;二层&quot;}]
</code></pre>
<p>生成的 html：</p>
<pre><code class="language-html">&lt;h1 name=&quot;item-1&quot;&gt;一层&lt;/h1&gt;
&lt;p&gt;文本&lt;/p&gt;
&lt;h2 name=&quot;item-2&quot;&gt;二层&lt;/h2&gt;
&lt;p&gt;文本&lt;/p&gt;
</code></pre>
<h1 id="item-3">设置锚点</h1>
<p>在页面中添加锚点，点击锚点跳转到对应标题的位置。</p>
<pre><code class="language-html">&lt;a href=&quot;#item-1&quot;&gt;一层&lt;/a&gt;
&lt;a href=&quot;#item-2&quot;&gt;二层&lt;/a&gt;
</code></pre>
</div>
  </div>

  <div class="sliber-wrap">
    
<div class="toc-wrap">
  <div class="title">文章目录</div>
  
  <a class="toc-item line-clamp-multi-1 " anchor="item-1" href="1628676905637.html#item-1">修改渲染规则</a>
  
  <a class="toc-item line-clamp-multi-1 " anchor="item-2" href="1628676905637.html#item-2">结果</a>
  
  <a class="toc-item line-clamp-multi-1 " anchor="item-3" href="1628676905637.html#item-3">设置锚点</a>
  
</div>



  </div>
</div>

  </div>

  <script src="static/pages/article_details/index.js?v=1.0.0.2022.08.13 10:12:50"></script>

  <script src="static/components/socket/index.js"></script>

</body>

</html>